import json
from datetime import datetime
from decimal import Decimal

from django.http import JsonResponse, HttpResponseBadRequest
from django.views import View

from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.order.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.viewmixin import LoginMixin

# http://www.meiduo.site:8800/orders/settlement/
"""
订单页面的显示
"""


class OrderSettlementView(LoginMixin, View):
    def get(self, request):
        # 获取用户对象
        user = request.user
        # 查询出当前用户的所有收货地址
        adds = Address.objects.filter(user=user, is_deleted=False)

        # 组织收货地址数据
        addresses_list = []
        for address in adds:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile,
            })

        # 连接redis  取出用户选中的购物车商品
        redis_conn = get_redis_connection('carts')
        cart_data = redis_conn.hgetall('cart_%s' % user.id)
        select_data = redis_conn.smembers('selected_%s' % user.id)

        new_cart_dict = {}
        for sku_id in select_data:
            count = cart_data[sku_id]
            new_cart_dict[int(sku_id)] = int(count)
        try:
            skus = SKU.objects.filter(id__in=new_cart_dict.keys())
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '查询失败'})

        # 组织商品数据
        sku_list = []
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'count': new_cart_dict[sku.id],
                'default_image_url': sku.default_image.url if sku.default_image else "",
            })

        context = {
            'addresses': addresses_list,
            'skus': sku_list,
            'freight': Decimal('10.00')
        }
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})


# http://www.meiduo.site:8800/orders/commit/
"""
订单提交的逻辑
"""


class CommitOrder(LoginMixin, View):
    def post(self, request):
        # 获取到user
        user = request.user

        # 获取参数 收货地址id  付款方式
        json_data = json.loads(request.body)
        address_id = json_data.get('address_id')
        pay_method = json_data.get('pay_method')

        # 校验参数  是否都存在
        if not all([address_id, pay_method]):
            return HttpResponseBadRequest('缺少参数')

        # 收货地址是否存在
        try:
            Address.objects.get(id=address_id)
        except Exception as e:
            print(e)
            return HttpResponseBadRequest('参数错误')

        # 付款方式是否存在
        if pay_method not in {OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']}:
            return HttpResponseBadRequest('参数错误')

        # 生成订单号
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)

        # 定义订单里面商品的总数量 和 总价钱
        total_count = 0
        total_amount = 0

        # 运费
        freight = Decimal('10.00')
        # 订单状态
        status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else \
            OrderInfo.ORDER_STATUS_ENUM['UNSEND']

        # 开始事务
        from django.db import transaction
        with transaction.atomic():
            # 设置回滚点
            save_id = transaction.savepoint()
            try:
                # 订单存入数据库
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user_id=user.id,
                    address_id=address_id,
                    total_count=total_count,
                    total_amount=total_amount,
                    freight=freight,
                    pay_method=pay_method,
                    status=status
                )
            except Exception as e:
                print(e)
                # 保存失败返回回滚点
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': 400, 'errmsg': '保存失败'})

            # 连接redis
            redis_conn = get_redis_connection('carts')
            # 取出购物车内选中的数据  里面数据为二进制
            carts_dict = redis_conn.hgetall('cart_%s' % user.id)
            selected_list = redis_conn.smembers('selected_%s' % user.id)
            # 创建新字典存放不是二进制的数据
            new_cart_dict = {}
            # 遍历选中的商品id列表
            for sku_id in selected_list:
                # 取出数量
                count = carts_dict[sku_id]
                # 存入新字典 转为int
                new_cart_dict[int(sku_id)] = int(count)

            try:
                # 查询出所有商品
                skus = SKU.objects.filter(id__in=new_cart_dict.keys(), is_launched=True)
            except Exception as e:
                print(e)
                # 查询失败返回回滚点
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': 400, 'errmsg': '查询失败'})

            # 遍历商品列表
            for sku in skus:
                # 添加死循环  一直来检测商品库存是否还有
                while True:
                    # 记录原数据库中商品的库存和销量
                    origin_stock = sku.stock
                    origin_sales = sku.sales
                    # 算出每一个商品的数量是否大于库存
                    count = new_cart_dict[sku.id]
                    if count > sku.stock:
                        # 库存不足返回到回滚点
                        transaction.savepoint_rollback(save_id)
                        return JsonResponse({'code': 400, 'errmsg': '库存不足'})
                    # 计算库存和销量
                    new_stock = origin_stock - count
                    new_sales = origin_sales + count
                    # time.sleep(5)
                    # 如果库存与保存库存的数据相等就说明中间没有人买同一个商品  过滤出数据再去修改库存和销量
                    # 结果返回的是过滤出的数据  有一条就返回1
                    result = SKU.objects.filter(id=sku.id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                    # 如果没有过滤出数据就说明库存与一开始不同了  数据改变了  跳过本次循环  继续执行
                    if result == 0:
                        continue

                    # 库存减去购买的数量
                    # sku.stock -= count
                    # 销量加上购买的数量
                    # sku.sales += count
                    # 保存到数据库
                    # sku.save()

                    try:
                        # 保存订单商品
                        OrderGoods.objects.create(
                            order_id=order_id,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )
                    except Exception as e:
                        print(e)
                        # 保存失败返回回滚点
                        transaction.savepoint_rollback(save_id)
                        return JsonResponse({'code': 400, 'errmsg': '保存失败'})

                    # 订单总数量+=每一个商品的数量  总价+=每一个商品的总价
                    order.total_count += count
                    order.total_amount += count * sku.price
                    # 如果执行下来没有continue就结束死循环来保存数据库
                    break

            # 总价+=运费
            order.total_amount += order.freight
            # 保存到数据库
            order.save()

            # 删除购物车里面生成了订单商品
            redis_conn.hdel('cart_%s' % user.id, *selected_list)
            redis_conn.srem('selected_%s' % user.id, *selected_list)
            # 提交事务
            transaction.savepoint_commit(save_id)

        # 返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})
